package com.nageoffer.shortlink.project.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.StrBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nageoffer.shortlink.project.common.convention.exception.ServiceException;
import com.nageoffer.shortlink.project.dao.entity.ShortLinkDO;
import com.nageoffer.shortlink.project.dao.mapper.ShortLinkMapper;
import com.nageoffer.shortlink.project.dto.req.ShortLinkCreateReqDTO;
import com.nageoffer.shortlink.project.dto.req.ShortLinkPageReqDTO;
import com.nageoffer.shortlink.project.dto.resp.ShortLinkCreateRespDTO;
import com.nageoffer.shortlink.project.dto.resp.ShortLinkPageRespDTO;
import com.nageoffer.shortlink.project.service.ShortLinkService;
import com.nageoffer.shortlink.project.toolkit.HashUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;


/**
 * 短链接接口实现层
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ShortLinkServiceImpl extends ServiceImpl<ShortLinkMapper, ShortLinkDO> implements ShortLinkService {

    /// 构造器方式注入布隆过滤器 记得加@RequiredArgsConstructor注解
    private final RBloomFilter<String> shortUriCreateCachePenetrationBloomFilter;

    @Override
    public ShortLinkCreateRespDTO createShortLink(ShortLinkCreateReqDTO reqParam) {

        String shortLinkSuffix = generateSuffix(reqParam);
        String fullShortUrl = StrBuilder.create(reqParam.getDomain())
                .append("/")
                .append(shortLinkSuffix)
                .toString();///reqParam.getDomain() + "/" + shortLinkSuffix的变体，更加优雅了

        ShortLinkDO.builder()
                .domain(reqParam.getDomain())
                .originUrl(reqParam.getOriginUrl())
                .gid(reqParam.getGid())
                .createdType(reqParam.getCreatedType())
                .validDateType(reqParam.getValidDateType())
                .validDate(reqParam.getValidDate())
                .describe(reqParam.getDescribe())
                .shortUri(shortLinkSuffix)
                .enableStatus(0)
                .fullShortUrl(fullShortUrl)
                .build();
        ShortLinkDO shortLinkDO = BeanUtil.toBean(reqParam, ShortLinkDO.class);
        shortLinkDO.setShortUri(shortLinkSuffix);
        shortLinkDO.setEnableStatus(0);
        shortLinkDO.setFullShortUrl(reqParam.getDomain() + "/" + shortLinkSuffix);

        try{
            baseMapper.insert(shortLinkDO);
        } catch (DuplicateKeyException ex) {
            /// 已经误判的短链接应该怎么处理？
            // 第一种，短链接确实真实存在于缓存中
            // 第二种，短链接不一定存在于缓存中
            LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
                            .eq(ShortLinkDO::getFullShortUrl, fullShortUrl);
            ShortLinkDO hasShortLinkDO = baseMapper.selectOne(queryWrapper);
            if(hasShortLinkDO!=null){
                log.warn("短链接：{} 重复入库",fullShortUrl);
                throw new ServiceException("短链接生成重复");
            }

        }
        shortUriCreateCachePenetrationBloomFilter.add(fullShortUrl);
        return ShortLinkCreateRespDTO.builder()
                .fullShortUrl(shortLinkDO.getFullShortUrl())
                .originUrl(reqParam.getOriginUrl())
                .gid(reqParam.getGid())
                .build();
    }

    @Override
    public IPage<ShortLinkPageRespDTO> pageShortLink(ShortLinkPageReqDTO requestParam) {
        LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
                .eq(ShortLinkDO::getGid, requestParam.getGid())
                .eq(ShortLinkDO::getEnableStatus, 0)
                .eq(ShortLinkDO::getDelFlag,0)
                .orderByDesc(ShortLinkDO::getCreateTime);
        IPage<ShortLinkDO> resultPage = baseMapper.selectPage(requestParam,queryWrapper);
        return resultPage.convert(each->BeanUtil.toBean(each,ShortLinkPageRespDTO.class));
    }

    private String generateSuffix(ShortLinkCreateReqDTO requestDTO) {
        // customGenerateCount 自定义生成次数
        int customGenerateCount = 0;
        String shortUri;

        while(true){
            ///如果冲突了就一直生成，那么我们应该限制最大的重置次数
            if(customGenerateCount>10){
                throw new ServiceException("短链接频繁生成，请稍后再试");
            }
            String originUrl =requestDTO.getOriginUrl();
            //添加当前时刻毫秒数
            originUrl += System.currentTimeMillis();
            shortUri=HashUtil.hashToBase62(originUrl);
            //使用布隆过滤器来做判断
            if(!shortUriCreateCachePenetrationBloomFilter.contains(requestDTO.getDomain() + "/" + shortUri)){
                break;
            }
            //生成重复最好的方法就是查一下是否重复
            //还要加一层分布式锁，而且最终稿要和数据库隔离开

            customGenerateCount++;
        }
        return shortUri;
    }

}
